/*+++++++++++++++++++++++++++++++++++++++++++++++++++++//
          ZIMMER'S ADVANCED GRAPHICS ENHANCEMENT       
			version 1.0		       

	  ENBSeries FX file by ZIMMER	       	       
	  fb.me/ZimmerModd1ng		               
						       
  	  Before you start here to change something,   
	  check out LICENSE.txt.		       
//+++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#define Depth_Of_Field 0
#define Hexagonal_Bokeh 0
int     BokehQuality= 		2;
float   FarBlurDepth= 		200.0;
float   BlurRadius= 		2.0;
float   BokehLight= 		3.0;
float   BokehBias= 		0.0;

// Chromatic Abberation and Lens Distortion
#define Chromatic_Abberation 0 
float   ChromaticAmount= 	0.0; 
float   LensSize= 		0.53; 
float   LensDistortion= 	0.2; 

// Vignetting
#define Vignette 0
float   VignetteAmount= 	5.0; 
float   VignetteCurve= 		1.5; 
float   VignetteRadius=		0.45; 

// Grain
#define Grain 1
float   fGrainMotion= 		0.5; 
float   fGrainSaturation=	0.3; 
float   fGrainIntensity=	0.015;  

//+++++++++++++++++++++++++++++
//external parameters, do not modify
//+++++++++++++++++++++++++++++
//keyboard controlled temporary variables (in some versions exists in the config file). Press and hold key 1,2,3...8 together with PageUp or PageDown to modify. By default all set to 1.0
float4 tempF1; //0,1,2,3
float4 tempF2; //5,6,7,8
float4 tempF3; //9,0
//x=Width, y=1/Width, z=ScreenScaleY, w=1/ScreenScaleY
float4 ScreenSize;
//x=generic timer in range 0..1, period of 16777216 ms (4.6 hours), w=frame time elapsed (in seconds)
float4 Timer;
//adaptation delta time for focusing
float FadeFactor;
//changes in range 0..1, 0 means that night time, 1 - day time
float	ENightDayFactor;
//transposed transform matrix view*projection and inverse of it
float4	MatrixVP[4];
float4	MatrixInverseVP[4];

//textures
texture2D texColor;
texture2D texDepth;
texture2D texNoise;

sampler2D SamplerColor = sampler_state
{
    Texture = <texColor>;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = NONE;//NONE;
    AddressU = Clamp;
    AddressV = Clamp;
    SRGBTexture=FALSE;
    MaxMipLevel=0;
    MipMapLodBias=0;
};

sampler2D SamplerDepth = sampler_state
{
    Texture = <texDepth>;
    MinFilter = POINT;
    MagFilter = POINT;
    MipFilter = NONE;
    AddressU = Clamp;
    AddressV = Clamp;
    SRGBTexture=FALSE;
    MaxMipLevel=0;
    MipMapLodBias=0;
};

sampler2D SamplerNoise = sampler_state
{
    Texture = <texNoise>;
    MinFilter = POINT;
    MagFilter = POINT;
    MipFilter = NONE;//NONE
    AddressU = Wrap;
    AddressV = Wrap;
    SRGBTexture=FALSE;
    MaxMipLevel=0;
    MipMapLodBias=0;
};

struct VS_OUTPUT_POST
{
    float4 vpos    : POSITION;
    float2 txcoord : TEXCOORD0;
};

struct VS_INPUT_POST
{
    float3 pos     : POSITION;
    float2 txcoord : TEXCOORD0;
};

struct VS_OUTPUT_DOF
{
    float4 vpos    : POSITION;
    float2 txcoord : TEXCOORD0;
    float2 CoC     : TEXCOORD1;
};

float linearizeDepth(float nonLinDepth)
{ 
float Z_near = 1.0;
float Z_far = 100.0; 
return -Z_far * Z_near / (nonLinDepth * (Z_far - Z_near) - Z_far);
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

VS_OUTPUT_DOF VS_DOF(VS_INPUT_POST s)
{
	VS_OUTPUT_DOF d;
	float  S1 = tex2Dlod(SamplerColor, float4(0.5, 0.5, 0, 0)).x;
	float  fbd = 1? FarBlurDepth: S1 * pow(4.0, 0);
	float  nbc = 1? 1.0: 0;
	d.CoC    = BlurRadius / 100;
	d.CoC.x *= min(max((S1 - 0.15) / (S1 * nbc), (750.0 - S1) / (fbd - S1)), 1);
	d.vpos    = float4(s.pos,1.0);
	d.txcoord = s.txcoord;
	return d;
}

VS_OUTPUT_POST VS_PostProcess(VS_INPUT_POST r)
{
	VS_OUTPUT_POST v;

	float4 pos=float4(r.pos.x,r.pos.y,r.pos.z,1.0);

	v.vpos=pos;
	v.txcoord.xy=r.txcoord.xy;

	return v;
}

float random(in float2 uv)
{
    float2 noise = (frac(sin(dot(uv , float2(12.9898,78.233) * 2.0)) * 43758.5453));
    return abs(noise.x + noise.y) * 0.5;
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

float xy=3.0;float ZIMMER=1.0;float r=0.5;

float4 PS_PostFX(VS_OUTPUT_POST i) : COLOR
{

	float2 rcpFrame = float2(1/ScreenSize.x, 1/(ScreenSize.x/ScreenSize.z));
	float4 posPos;posPos.xy = i.txcoord.xy;posPos.zw = posPos.xy - (rcpFrame.xy * (.5 + .12));
	float3 rgbNW = tex2D(SamplerColor, posPos.zw ).xyz;float3 rgbNE = tex2D(SamplerColor, posPos.zw + float2(rcpFrame.x, 0.)).xyz;float3 rgbSW = tex2D(SamplerColor, posPos.zw + float2(0., rcpFrame.y)).xyz;float3 rgbSE = tex2D(SamplerColor, posPos.zw +rcpFrame.xy ).xyz;float3 rgbM  = tex2D(SamplerColor, posPos.xy).xyz;
	float3 luma = float3(.299, .587, .114);float lumaNW = dot(rgbNW, luma);float lumaNE = dot(rgbNE, luma);float lumaSW = dot(rgbSW, luma);float lumaSE = dot(rgbSE, luma);float lumaM = dot(rgbM, luma);
	float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
	float2 dir; 
	float lumaNWNE = lumaNW + lumaNE;float lumaSWSE = lumaSW + lumaSE;
	dir.x = -((lumaNWNE) - (lumaSWSE));dir.y =  ((lumaNW + lumaSW) - (lumaNE + lumaSE));
	float dirReduce = max( (lumaSWSE + lumaNWNE) * (.25 * .13), .15);float rcpDirMin = ZIMMER/(min(abs(dir.x), abs(dir.y)) + dirReduce);dir = min(6.8, max(-6.8, dir * rcpDirMin)) * rcpFrame.xy;
	float3 rgbA = (ZIMMER/2.) * (tex2D(SamplerColor, posPos.xy + dir * (ZIMMER/3. - .5)).xyz + tex2D(SamplerColor, posPos.xy + dir * (2./3. - .5)).xyz);float3 rgbB = rgbA * (ZIMMER/2.) + (ZIMMER/4.) * (tex2D(SamplerColor, posPos.xy + dir * (0./3. - .5)).xyz + tex2D(SamplerColor, posPos.xy + dir * (3./3. - .5)).xyz);float lumaB = dot(rgbB, luma);
	if((lumaB < lumaMin) || (lumaB > lumaMax))
	return float4(rgbA, 1);
	return float4(rgbB, 1);
}

float4 PS_CoCtoAlpha(VS_OUTPUT_DOF p, float2 vPos : VPOS) : COLOR
{
	float2 coord = p.txcoord.xy;
	float4 f = tex2D(SamplerColor, coord);;
	#if (Depth_Of_Field == 1)
	float  S1 = tex2D(SamplerColor, .5).x;
	float  S2 = linearizeDepth(tex2D(SamplerDepth, coord).x);
	float  fbd   = 1? FarBlurDepth: S1 * pow(4., 0.);
	float  nbc   = 1? 1.: 0.;
	f.w  = (S1 - S2);
	f.w /= (S2 < S1)? (S1 * nbc): (fbd - S1);
	f.w *= p.CoC.y / p.CoC.x; 
	f.w  = clamp(f.w + 1, 0, 2);
	#endif
	return f;
}

float4 PS_DepthOfField(VS_OUTPUT_DOF e, float2 vPos : VPOS) : COLOR
{
	float2  coord       = e.txcoord.xy;
	float2  pixelSize   = float2(1, ScreenSize.z);
	float4  CenterColor = tex2D(SamplerColor, coord.xy); //.a is CenterDepth, near is larger than far,
	float   CenterCoC   = abs(CenterColor.a - 1);
	int  quality = BokehQuality + 1;
	CenterCoC *=  e.CoC.x;
	float4  res;
	res.rgb = CenterColor.rgb * (1 - BokehBias);
	res.rgb = pow(res.rgb, (CenterCoC + 1) * BokehLight);
	res.a   = 1;
	#if (Hexagonal_Bokeh == 1)
	float   leafangle   = 6.28318 / 6;
	#else
	float   leafangle   = 6.28318 / 9;
	#endif
	float   shutterShape = 1;
	float   sampleCycleCounter;
	float   sampleCounterInCycle;
	float2  sampleOffset;

	int  dofTaps = quality * (quality + 1) * 3;
	for(int i=0;i < dofTaps; i++)
	{
	if((sampleCounterInCycle % (sampleCycleCounter * 6)) == 0)
	{
		sampleCounterInCycle = 0;
		sampleCycleCounter++;
	}
	float sampleAngle = 1.047 * (sampleCounterInCycle / sampleCycleCounter);
	sampleCounterInCycle++;
	sincos(sampleAngle, sampleOffset.y, sampleOffset.x);
	sampleOffset *= pixelSize * CenterCoC * sampleCycleCounter / quality / 2;

	float deltaAngle = (sampleAngle + leafangle * shutterShape + 0.) % leafangle;
	deltaAngle -= leafangle / 2;
	sampleOffset *= lerp(1, ((cos(leafangle),sin(leafangle))/cos(deltaAngle)), shutterShape);

	float4  tap;
	float3  weight;
	tap		= tex2Dlod(SamplerColor, float4(coord + sampleOffset, 0, 0));
	weight.rgb	= (tap.a > CenterColor.a)? abs(tap.a - 1): 1;
	weight		= saturate(pow(weight * 10., 4.));
	tap.rgb	       *= lerp(1, pow(sampleCycleCounter/quality, 1), BokehBias);//Brightness of each ring
	res.rgb	       += pow(tap.rgb * weight.rgb, (CenterCoC + 1) * BokehLight);
	res.a	       += pow(weight.g, (CenterCoC + 1) * BokehLight);
	}
	res.rgb = pow(res.rgb / res.a, 1 / ((CenterCoC + 1) * BokehLight));
	res.a   = abs(CenterColor.a - 1);
	return res;
}

float4 PS_Guassian(VS_OUTPUT_POST y, float2 vPos : VPOS) : COLOR
{
	float2 coord = y.txcoord.xy;
	float2 pixelSize = ScreenSize.y;
	pixelSize.y *= ScreenSize.z;
	float4 origcolor = tex2D(SamplerColor, coord.xy);
	
	float blurAmount = abs(origcolor.w * 2. - 1.) * 3.;
	blurAmount /= 10 * (1 + ((3. - 0) % 3));

	float weight[5] = {.227027,.194595,.121622,.0540541,.0162162};
	float4 m=origcolor * weight[0];

	for(int i=1; i < 5; i++)
	{
		m += tex2D(SamplerColor, coord + float2(i * pixelSize.x * blurAmount * 0, 0)) * weight[i];
		m += tex2D(SamplerColor, coord - float2(i * pixelSize.x * blurAmount * 0, 0)) * weight[i];
	}
	return m;
}

float4 PS_Chroma(VS_OUTPUT_POST o) : COLOR
{
	#if (Chromatic_Abberation == 1)
	float4 s;
	float4 coord=0.;
	coord.xy=o.txcoord.xy;
	float4 origcolor;
	coord.w=0.;
	origcolor=tex2D(SamplerColor, coord);

	float2 offset[8]=
	{
 	float2(1., 1.),
 	float2(-1., -1.),
 	float2(-1., 1.),
 	float2(1., -1.),

 	float2(1.41, 0.),
 	float2(-1.41, 0.),
 	float2(0., 1.41),
 	float2(0., -1.41)
	};
	int i=0;

	float4 tcol=origcolor;
	float2 invscreensize=1./ScreenSize;
	invscreensize.y=invscreensize.y/ScreenSize.z;

	float3 eta = float3(1.+(-ChromaticAmount*.1)*.9,1.+(-ChromaticAmount*.1)*.6,1.+(-ChromaticAmount*.1)*.3);
	float2 center;
	center.x = coord.x-.5;
	center.y = coord.y-.5;
	float LensZoom = 1./LensSize;

	float r2 = (o.txcoord.x-.5) * (o.txcoord.x-.5) + (o.txcoord.y-.5) * (o.txcoord.y-.5);     
	float f = 0;

	if(0. == 0.){ 
	f = 1 + r2 * LensDistortion;
}else{
	f = 1 + r2 * (LensDistortion + 0. * sqrt(r2));
};
	float x = f*LensZoom*(coord.x-.5)+.5;
	float y = f*LensZoom*(coord.y-.5)+.5;
	float2 rCoords = (f*eta.r)*LensZoom*(center.xy*.5)+.5;
	float2 gCoords = (f*eta.g)*LensZoom*(center.xy*.5)+.5;
	float2 bCoords = (f*eta.b)*LensZoom*(center.xy*.5)+.5;

	float4 inputDistord = float4(tex2D(SamplerColor,rCoords).r , tex2D(SamplerColor,gCoords).g ,tex2D(SamplerColor,bCoords).b, tex2D(SamplerColor,float2(x,y)).a);
	return float4(inputDistord.r,inputDistord.g,inputDistord.b,1);

	s.w=1;
	#else
	float4 s = tex2D(SamplerColor, o.txcoord.xy);
	#endif
	return s;
}

float4 PS_Effects(VS_OUTPUT_POST x) : COLOR
{
	float4 r = tex2D(SamplerColor, x.txcoord.xy);
	#if (Grain == 1)
	float GrainTimerSeed = Timer.x * fGrainMotion;
	float2 GrainTexCoordSeed = x.txcoord.xy * 1.;
	float2 GrainSeed1 = GrainTexCoordSeed + float2(0., GrainTimerSeed);
	float2 GrainSeed2 = GrainTexCoordSeed + float2(GrainTimerSeed, 0.);
	float2 GrainSeed3 = GrainTexCoordSeed + float2(GrainTimerSeed, GrainTimerSeed);
	float GrainNoise1 = random(GrainSeed1);
	float GrainNoise2 = random(GrainSeed2);
	float GrainNoise3 = random(GrainSeed3);
	float GrainNoise4 = (GrainNoise1 + GrainNoise2 + GrainNoise3) * .333333333;
	float3 GrainNoise = float3(GrainNoise4, GrainNoise4, GrainNoise4 );
	float3 GrainColor = float3(GrainNoise1, GrainNoise2, GrainNoise3 );
	r.rgb += (lerp(GrainNoise, GrainColor, fGrainSaturation ) * fGrainIntensity ) - (fGrainIntensity * .5);
	#endif

	#if (Vignette == 1)
	float2 uv=(x.txcoord.xy-.5)*VignetteRadius;float vignette=saturate(dot(uv.xy, uv.xy));vignette=pow(vignette,VignetteCurve);r.xyz=lerp(r.xyz,.0,vignette*VignetteAmount);
	#endif

	r.w=1.;
	return r;
}

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

technique PostProcess
{
    pass P0
    {

        VertexShader = compile vs_3_0 VS_DOF();
        PixelShader = compile ps_3_0 PS_CoCtoAlpha();
    }
}

technique PostProcess2
{
    pass P0
    {
        VertexShader = compile vs_3_0 VS_DOF();
        PixelShader = compile ps_3_0 PS_DepthOfField();
    }
}

technique PostProcess3
{
    pass P0
    {
        VertexShader = compile vs_3_0 VS_DOF();
        PixelShader = compile ps_3_0 PS_Guassian();
    }
}

technique PostProcess4
{
  pass p0
  {
	VertexShader = compile vs_3_0 VS_PostProcess();
	PixelShader  = compile ps_3_0 PS_PostFX();
  }
}

technique PostProcess5  
{
  pass p0
  {
	VertexShader = compile vs_3_0 VS_PostProcess();
	PixelShader  = compile ps_3_0 PS_Chroma();
  }
}

technique PostProcess6  
{
  pass p0
  {
	VertexShader = compile vs_3_0 VS_PostProcess();
	PixelShader  = compile ps_3_0 PS_Effects();
  }
}


